package com.gitee.wsl.common.ui.base

import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset
import com.gitee.wsl.common.ui.ext.dot
import com.gitee.wsl.common.ui.ext.mag
import com.gitee.wsl.common.ui.ext.sub
import com.gitee.wsl.math.Math
import com.gitee.wsl.unit.angle.AngleUnit
import com.gitee.wsl.unit.angle.ext.getPoint
import com.gitee.wsl.unit.angle.toRadians


typealias Point = Offset

@Stable
fun Point(x: Int , y: Int ) = Offset(x.toFloat(), y.toFloat())

@Stable
fun Point(x: Float = 0f, y: Float = 0f) = Offset(x, y)

@Stable
fun Point(x: Double, y: Double) = Offset(x.toFloat(), y.toFloat())


/**
 * Dot product of 2 vectors.
 */
internal operator fun Point.times(vector: Point): Float = dot(vector)

internal operator fun Float.times(vector: Point): Point = vector.times(this)

fun Point.perpendicular() = Point(-y,x)

fun Point.perpendicular(p1:Point,p2:Point):Point{
    var x6 = p1.x + p2.x
    var y6 = p1.y + p2.y

    val a = p2.x * y6 - p2.y * x6

    if (a < 0.01 && a > -0.01) {
        /* Almost straight */
        x6 = -p2.y
        y6 = p2.x
    } else {
        x6 /= a
        y6 /= a
    }
    return Point(x6,y6)
}

// 平移点
fun Point.translate(x: Float, y: Float): Point = Point(this.x + x, this.y + y)

fun Point.moveLeft(x: Float): Point = translate( -x, 0f)

fun Point.moveRight(x: Float): Point = translate( x, 0f)

fun Point.moveUp(y: Float): Point = translate( 0f, -y)

fun Point.moveDown(y: Float): Point = translate( 0f, y)


/**
 * Calculates Euclidean distance between two vectors
 */
fun Point.distance(other: Point): Float = this.copy().sub(other).mag()

fun Point.distance(x:Float,y:Float)= distance(Point(x,y))


fun Point.center(p2: Point) = Point((x + p2.x) / 2, (y + p2.y) / 2)

fun Point.percentAt(p2: Point, percent: Float) = Math.percentAt(this,percent, p2, percent)

fun Math.percentAt(p1: Point, percent1: Float, p2: Point, percent2: Float): Point {
    val x = (p2.x - p1.x) * percent1 + p1.x
    val y = (p2.y - p1.y) * percent2 + p1.y
    return Point(x, y)
}
//如果有NaN就置0
fun Point.avoidNaN() = if (x.isNaN() || y.isNaN()) Point(0f, 0f) else this

fun Point.degreeWith(p2:Point):AngleUnit = Math.getRadian(this.x,this.y,p2.x,p2.y).toRadians()

fun Point.move(p2:AngleUnit,distance:Float):Point = p2.getPoint(this,distance)


/**
 * Compute the Z coordinate of the cross product of two vectors, to check if the second vector is
 * going clockwise ( > 0 ) or counterclockwise (< 0) compared with the first one.
 * It could also be 0, if the vectors are co-linear.
 */
fun Point.clockwise(other: Point) = x * other.y - y * other.x > 0

/**
 * Linearly interpolate between two Points.
 *
 * The [fraction] argument represents position on the timeline, with 0.0 meaning
 * that the interpolation has not started, returning [start] (or something
 * equivalent to [start]), 1.0 meaning that the interpolation has finished,
 * returning [stop] (or something equivalent to [stop]), and values in between
 * meaning that the interpolation is at the relevant point on the timeline
 * between [start] and [stop]. The interpolation can be extrapolated beyond 0.0 and
 * 1.0, so negative values and values greater than 1.0 are valid (and can
 * easily be generated by curves).
 *
 * Values for [fraction] are usually obtained from an [Animation<Float>], such as
 * an `AnimationController`.
 */
//internal fun interpolate(start: Point, stop: Point, fraction: Float): Point {
//    return Point(
//        interpolate(start.x, stop.x, fraction),
//        interpolate(start.y, stop.y, fraction)
//    )
//}

//internal fun Point.transformed(f: PointTransformer): Point {
//    val result = f.transform(x, y)
//    return Point(result.first, result.second)
//}